package com.unionpay.resource;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Timer;

import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

import org.apache.log4j.Logger;

import com.unionpay.async.NewTimerTask;
import com.unionpay.bean.ReqAdvAuth;
import com.unionpay.bean.ReqAdvInput;
import com.unionpay.bean.ReqAnchor;
import com.unionpay.bean.ReqAnchorCofig;
import com.unionpay.bean.ReqAnchorRecord;
import com.unionpay.bean.ReqAuth;
import com.unionpay.bean.ReqBlockInfo;
import com.unionpay.bean.ReqGetAnchorCofig;
import com.unionpay.bean.ReqInput;
import com.unionpay.bean.ReqNodeUrl;
import com.unionpay.bean.ReqQueryAcc;
import com.unionpay.bean.Request;
import com.unionpay.bean.Response;
import com.unionpay.config.Config;
import com.unionpay.db.TblAnchorcofig;
import com.unionpay.db.TblAnchorrecord;
import com.unionpay.db.TblDailytxid;
import com.unionpay.db.TblInputtochain;
import com.unionpay.db.TblQueryfromchain;
import com.unionpay.db.TblUser;
import com.unionpay.entity.AnchorcofigEntity;
import com.unionpay.entity.AnchorrecordEntity;
import com.unionpay.entity.InputtochainEntity;
import com.unionpay.rpc.Data;
import com.unionpay.rpc.DataArr;
import com.unionpay.rpc.DataObj;
import com.unionpay.rpc.DataStr;
import com.unionpay.rpc.Rpc;
import com.unionpay.rpc.RpcMethod;
import com.unionpay.util.DateUtil;
import com.unionpay.util.JSON;
import com.unionpay.util.SHA1;
import com.unionpay.util.StrUtil;

/**
 * API
 * 
 * @author 瞿峰
 * @since 2016年5月4日
 */
@Path("/")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public class NewResource {
	private static Logger logger = Logger.getLogger(NewResource.class);

	@POST
	@Path("/v1/inputtochain")
	public Response inputtochain(ReqInput req) {
		logger.info("req: " + JSON.toJson(req));
		Response res = new Response();
		String nodeurl = null;
		String bizid = req.getBizid();
		String noncestr = req.getNoncestr();
		String signdata = req.getSigndata();
		ReqInput.Data data = null;
		String input = null;
		String from = null;
		String to = null;
		if (StrUtil.hasEmpty(bizid, noncestr, signdata) //
				|| noncestr.length() != Request.NONCESTR_LENGTH //
				|| (data = req.getData()) == null //
				|| !StrUtil.isUrl(nodeurl = data.getNodeurl()) //
				|| ((from = data.getFrom()) != null && !StrUtil.is0x40(from)) //
				|| ((to = data.getTo()) != null && !StrUtil.is0x40(to))) { //
			res.setError("495");
			return res(res);
		}

		if ((input = data.getInput()) == null || !StrUtil.is0x128(input)) {
			res.setError("494");
			return res(res);
		}
		String bizkey = null;
		if (!StrUtil.is0x40(bizid)
				|| (bizkey = TblUser.queryById(bizid)) == null) {
			res.setError("496");
			return res(res);
		}
		if (!isSign(signdata, bizkey, noncestr, req.getData())) {
			res.setError("497");
			return res(res);
		}
		if (from == null) {
			from = bizid;
		}
		input += bizid.substring(2);
		input += DateUtil.getDateTime(new Date());
		RpcMethod transMethod = new RpcMethod(Rpc.ETH_SENDTRANSACTION);
		if (to == null) {
			transMethod.addParams(from, input);
		} else {
			transMethod.addParams(from, to, input);
		}
		Data dd = Rpc.request(nodeurl, transMethod);
		String transactionid = null;
		if (dd instanceof DataStr) {
			transactionid = ((DataStr) dd).getResult();
			res.getResponse().setTransactionid(transactionid);
			// 同步记录交易
			TblInputtochain
					.save(nodeurl, bizid, from, to, input, transactionid);
			// 查询是否有定时任务
			AnchorcofigEntity entity = TblAnchorcofig.selectByBizId(bizid);
			if (entity != null) {
				NewTimerTask.startbyrecord(entity.getAnchortype(), bizid,
						entity.getAnchorcofigid(),
						Integer.parseInt(entity.getAnchorrecords()));
			}
		} else if (dd == null) {
			res.setError("498");
			return res(res);
		} else {
			res.setError("499");
			return res(res);
		}
		// 异步记录交易
		// TblInputtochain.asyncSave(nodeurl, bizid, from, to, input,
		// transactionid);
		// 异步查询交易详情并入库
		// if (transactionid != null) {
		// TblTransaction.asyncSave(transactionid);
		// }
		return res(res);
	}

	@POST
	@Path("/v1/queryfromchain")
	public Response queryfromchain(ReqAuth req) {
		logger.info("req: " + JSON.toJson(req));
		Response res = new Response();
		String nodeurl = null;
		String bizid = req.getBizid();
		String noncestr = req.getNoncestr();
		String signdata = req.getSigndata();
		ReqAuth.Data data = null;
		String transactionid = null;
		if (StrUtil.hasEmpty(bizid, noncestr, signdata) //
				|| noncestr.length() != Request.NONCESTR_LENGTH //
				|| (data = req.getData()) == null //
				|| !StrUtil.isUrl(nodeurl = data.getNodeurl()) //
				|| (transactionid = data.getTransactionid()) == null //
				|| !StrUtil.is0x64(transactionid)) {//
			res.setError("495");
			return res(res);
		}
		String bizkey = null;
		if (!StrUtil.is0x40(bizid)
				|| (bizkey = TblUser.queryById(bizid)) == null) {
			res.setError("496");
			return res(res);
		}
		if (!isSign(signdata, bizkey, noncestr, req.getData())) {
			res.setError("497");
			return res(res);
		}
		RpcMethod method = new RpcMethod(Rpc.ETH_GETTRANSACTIONBYHASH);
		method.addParams(transactionid);
		Data dd = Rpc.request(nodeurl, method);
		Response.Data resData = null;
		if (dd instanceof DataObj) {
			DataObj.Trade trade = ((DataObj) dd).getResult();
			resData = res.new Data();
			String input = trade.getInput();
			String blockNumber = trade.getBlockNumber();
			String index = trade.getTransactionIndex();
			if (!StrUtil.hasEmpty(input)) {
				if (input.startsWith("0x")) {
					input = input.substring(2);
				}
				if (input.length() > 128) {
					input = input.substring(0, 128);
				}
			}
			resData.setBlockHash(trade.getBlockHash());
			resData.setBlockNumber(StrUtil.Hex2Int(blockNumber));
			resData.setContent(input);
			resData.setTransactionIndex(StrUtil.Hex2Int(index));
			res.setResponse(resData);
		} else if (dd == null) {
			res.setError("498");
			return res(res);
		} else {
			res.setError("499");
			return res(res);
		}
		// 同步保存
		// TblAuthfromchain.save(nodeurl, bizid, transactionid,
		// resData.getBlockHash(), resData.getBlockNumber(),
		// resData.getContent(), resData.getTransactionIndex());
		// 异步保存
		TblQueryfromchain.asyncSave(nodeurl, bizid, transactionid,
				resData.getBlockHash(), resData.getBlockNumber(),
				resData.getContent(), resData.getTransactionIndex());
		return res(res);
	}

	@POST
	@Path("/v1/queryClientInfo")
	public Response queryClientInfo(ReqNodeUrl req) {
		logger.info("req: " + JSON.toJson(req));
		Response res = new Response();
		String nodeurl = null;
		String bizid = req.getBizid();
		String noncestr = req.getNoncestr();
		String signdata = req.getSigndata();
		ReqNodeUrl.Data data = null;
		if (StrUtil.hasEmpty(bizid, noncestr, signdata) //
				|| noncestr.length() != Request.NONCESTR_LENGTH //
				|| (data = req.getData()) == null //
				|| !StrUtil.isUrl(nodeurl = data.getNodeurl())) {//
			res.setError("495");
			return res(res);
		}
		String bizkey = null;
		if (!StrUtil.is0x40(bizid)
				|| (bizkey = TblUser.queryById(bizid)) == null) {
			res.setError("496");
			return res(res);
		}
		if (!isSign(signdata, bizkey, noncestr, req.getData())) {
			res.setError("497");
			return res(res);
		}
		RpcMethod method1 = new RpcMethod(Rpc.ETH_PROTOCOLVERSION);
		RpcMethod method2 = new RpcMethod(Rpc.WEB3_CLIENTVERSION);
		RpcMethod method3 = new RpcMethod(Rpc.NET_VERSION);
		RpcMethod method4 = new RpcMethod(Rpc.NET_LISTENING);
		Data dd1 = Rpc.request(nodeurl, method1);
		Data dd2 = Rpc.request(nodeurl, method2);
		Data dd3 = Rpc.request(nodeurl, method3);
		Data dd4 = Rpc.request(nodeurl, method4);
		String ethereumVersion = null;
		String clientVersion = null;
		String netVersion = null;
		String listening = null;
		if (dd1 instanceof DataStr) {
			ethereumVersion = ((DataStr) dd1).getResult();
			res.getResponse().setEthereumVersion(
					StrUtil.Hex2Int(ethereumVersion));
		} else if (dd1 == null) {
			res.setError("498");
			return res(res);
		} else {
			res.setError("499");
			return res(res);
		}
		if (dd2 instanceof DataStr) {
			clientVersion = ((DataStr) dd2).getResult();
			res.getResponse().setClientVersion(clientVersion);
		} else if (dd2 == null) {
			res.setError("498");
			return res(res);
		} else {
			res.setError("499");
			return res(res);
		}
		if (dd3 instanceof DataStr) {
			netVersion = ((DataStr) dd3).getResult();
			res.getResponse().setNetVersion(netVersion);
		} else if (dd3 == null) {
			res.setError("498");
			return res(res);
		} else {
			res.setError("499");
			return res(res);
		}
		if (dd4 instanceof DataStr) {
			listening = ((DataStr) dd4).getResult();
			res.getResponse().setListening(listening);
		} else if (dd4 == null) {
			res.setError("498");
			return res(res);
		} else {
			res.setError("499");
			return res(res);
		}
		return res(res);
	}

	@POST
	@Path("/v1/listaccounts")
	public Response listaccounts(ReqNodeUrl req) {
		logger.info("req: " + JSON.toJson(req));
		Response res = new Response();
		String nodeurl = null;
		String bizid = req.getBizid();
		String noncestr = req.getNoncestr();
		String signdata = req.getSigndata();
		ReqNodeUrl.Data data = null;
		if (StrUtil.hasEmpty(bizid, noncestr, signdata) //
				|| noncestr.length() != Request.NONCESTR_LENGTH //
				|| (data = req.getData()) == null //
				|| !StrUtil.isUrl(nodeurl = data.getNodeurl())) {//
			res.setError("495");
			return res(res);
		}
		String bizkey = null;
		if (!StrUtil.is0x40(bizid)
				|| (bizkey = TblUser.queryById(bizid)) == null) {
			res.setError("496");
			return res(res);
		}
		if (!isSign(signdata, bizkey, noncestr, req.getData())) {
			res.setError("497");
			return res(res);
		}
		RpcMethod method = new RpcMethod(Rpc.ETH_ACCOUNTS);
		Data dd = Rpc.request(nodeurl, method);
		ArrayList<String> allaccounts = null;
		if (dd instanceof DataArr) {
			allaccounts = ((DataArr) dd).getResult();
			res.getResponse().setAllaccounts(allaccounts);
		} else if (dd == null) {
			res.setError("498");
			return res(res);
		} else {
			res.setError("499");
			return res(res);
		}

		return res(res);
	}

	@POST
	@Path("/v1/syncing")
	public Response syncing(ReqNodeUrl req) {
		logger.info("req: " + JSON.toJson(req));
		Response res = new Response();
		String nodeurl = null;
		String bizid = req.getBizid();
		String noncestr = req.getNoncestr();
		String signdata = req.getSigndata();
		ReqNodeUrl.Data data = null;
		if (StrUtil.hasEmpty(bizid, noncestr, signdata) //
				|| noncestr.length() != Request.NONCESTR_LENGTH //
				|| (data = req.getData()) == null //
				|| !StrUtil.isUrl(nodeurl = data.getNodeurl())) {//
			res.setError("495");
			return res(res);
		}
		String bizkey = null;
		if (!StrUtil.is0x40(bizid)
				|| (bizkey = TblUser.queryById(bizid)) == null) {
			res.setError("496");
			return res(res);
		}
		if (!isSign(signdata, bizkey, noncestr, req.getData())) {
			res.setError("497");
			return res(res);
		}
		RpcMethod method = new RpcMethod(Rpc.ETH_SYNCING);
		Data dd = Rpc.request(nodeurl, method);
		Object result;
		if (dd instanceof DataStr || dd instanceof DataObj) {
			result = ((DataStr) dd).getResult();
			res.getResponse().setResult(result);
		} else if (dd == null) {
			res.setError("498");
			return res(res);
		} else {
			res.setError("499");
			return res(res);
		}

		return res(res);
	}

	@POST
	@Path("/v1/mining")
	public Response mining(ReqNodeUrl req) {
		logger.info("req: " + JSON.toJson(req));
		Response res = new Response();
		String nodeurl = null;
		String bizid = req.getBizid();
		String noncestr = req.getNoncestr();
		String signdata = req.getSigndata();
		ReqNodeUrl.Data data = null;
		if (StrUtil.hasEmpty(bizid, noncestr, signdata) //
				|| noncestr.length() != Request.NONCESTR_LENGTH //
				|| (data = req.getData()) == null //
				|| !StrUtil.isUrl(nodeurl = data.getNodeurl())) {//
			res.setError("495");
			return res(res);
		}
		String bizkey = null;
		if (!StrUtil.is0x40(bizid)
				|| (bizkey = TblUser.queryById(bizid)) == null) {
			res.setError("496");
			return res(res);
		}
		if (!isSign(signdata, bizkey, noncestr, req.getData())) {
			res.setError("497");
			return res(res);
		}
		RpcMethod method = new RpcMethod(Rpc.ETH_MINING);
		Data dd = Rpc.request(nodeurl, method);
		Object result;
		if (dd instanceof DataStr) {
			result = ((DataStr) dd).getResult();
			res.getResponse().setResult(result);
		} else if (dd == null) {
			res.setError("498");
			return res(res);
		} else {
			res.setError("499");
			return res(res);
		}

		return res(res);
	}

	@POST
	@Path("/v1/queryHashRate")
	public Response queryHashRate(ReqNodeUrl req) {
		logger.info("req: " + JSON.toJson(req));
		Response res = new Response();
		String nodeurl = null;
		String bizid = req.getBizid();
		String noncestr = req.getNoncestr();
		String signdata = req.getSigndata();
		ReqNodeUrl.Data data = null;
		if (StrUtil.hasEmpty(bizid, noncestr, signdata) //
				|| noncestr.length() != Request.NONCESTR_LENGTH //
				|| (data = req.getData()) == null //
				|| !StrUtil.isUrl(nodeurl = data.getNodeurl())) {//
			res.setError("495");
			return res(res);
		}
		String bizkey = null;
		if (!StrUtil.is0x40(bizid)
				|| (bizkey = TblUser.queryById(bizid)) == null) {
			res.setError("496");
			return res(res);
		}
		if (!isSign(signdata, bizkey, noncestr, req.getData())) {
			res.setError("497");
			return res(res);
		}
		RpcMethod method = new RpcMethod(Rpc.ETH_HASHRATE);
		Data dd = Rpc.request(nodeurl, method);
		String hashRate = null;
		if (dd instanceof DataStr) {
			hashRate = ((DataStr) dd).getResult();
			res.getResponse().setHashRate(StrUtil.Hex2Int(hashRate));
		} else if (dd == null) {
			res.setError("498");
			return res(res);
		} else {
			res.setError("499");
			return res(res);
		}

		return res(res);
	}

	@POST
	@Path("/v1/queryRewardAcc")
	public Response queryRewardAcc(ReqNodeUrl req) {
		logger.info("req: " + JSON.toJson(req));
		Response res = new Response();
		String nodeurl = null;
		String bizid = req.getBizid();
		String noncestr = req.getNoncestr();
		String signdata = req.getSigndata();
		ReqNodeUrl.Data data = null;
		if (StrUtil.hasEmpty(bizid, noncestr, signdata) //
				|| noncestr.length() != Request.NONCESTR_LENGTH //
				|| (data = req.getData()) == null //
				|| !StrUtil.isUrl(nodeurl = data.getNodeurl())) {//
			res.setError("495");
			return res(res);
		}
		String bizkey = null;
		if (!StrUtil.is0x40(bizid)
				|| (bizkey = TblUser.queryById(bizid)) == null) {
			res.setError("496");
			return res(res);
		}
		if (!isSign(signdata, bizkey, noncestr, req.getData())) {
			res.setError("497");
			return res(res);
		}
		RpcMethod method = new RpcMethod(Rpc.ETH_COINBASE);
		Data dd = Rpc.request(nodeurl, method);
		String rewardAccount = null;
		if (dd instanceof DataStr) {
			rewardAccount = ((DataStr) dd).getResult();
			res.getResponse().setRewardAccount(rewardAccount);
		} else if (dd == null) {
			res.setError("498");
			return res(res);
		} else {
			res.setError("499");
			return res(res);
		}

		return res(res);
	}

	@POST
	@Path("/v1/queryblocknum")
	public Response queryblocknum(ReqNodeUrl req) {
		logger.info("req: " + JSON.toJson(req));
		Response res = new Response();
		String nodeurl = null;
		String bizid = req.getBizid();
		String noncestr = req.getNoncestr();
		String signdata = req.getSigndata();
		ReqNodeUrl.Data data = null;
		if (StrUtil.hasEmpty(bizid, noncestr, signdata) //
				|| noncestr.length() != Request.NONCESTR_LENGTH //
				|| (data = req.getData()) == null //
				|| !StrUtil.isUrl(nodeurl = data.getNodeurl())) {//
			res.setError("495");
			return res(res);
		}
		String bizkey = null;
		if (!StrUtil.is0x40(bizid)
				|| (bizkey = TblUser.queryById(bizid)) == null) {
			res.setError("496");
			return res(res);
		}
		if (!isSign(signdata, bizkey, noncestr, req.getData())) {
			res.setError("497");
			return res(res);
		}
		RpcMethod method = new RpcMethod(Rpc.ETH_BLOCKNUMBER);
		Data dd = Rpc.request(nodeurl, method);
		String blocknumber = null;
		if (dd instanceof DataStr) {
			blocknumber = ((DataStr) dd).getResult();
			res.getResponse().setBlocknumber(StrUtil.Hex2Int(blocknumber));
		} else if (dd == null) {
			res.setError("498");
			return res(res);
		} else {
			res.setError("499");
			return res(res);
		}

		return res(res);
	}

	@POST
	@Path("/v1/queryblockinfo")
	public Response queryblockinfo(ReqBlockInfo req) {
		logger.info("req: " + JSON.toJson(req));
		Response res = new Response();
		String nodeurl = null;
		String bizid = req.getBizid();
		String noncestr = req.getNoncestr();
		String signdata = req.getSigndata();
		ReqBlockInfo.Data data = null;
		if (StrUtil.hasEmpty(bizid, noncestr, signdata) //
				|| noncestr.length() != Request.NONCESTR_LENGTH //
				|| (data = req.getData()) == null //
				|| !StrUtil.isUrl(nodeurl = data.getNodeurl())
				|| StrUtil.isUrl(data.getQueryType())) {//
			res.setError("495");
			return res(res);
		}
		String queryType = data.getQueryType();
		String blockNumber = data.getBlockNumber();
		String blockHash = data.getBlockHash();
		if (!"1".equals(queryType) && !"2".equals(queryType)) {
			res.setError("495");
			return res(res);
		} else if ("1".equals(queryType) && StrUtil.hasEmpty(blockHash)) {
			res.setError("495");
			return res(res);
		} else if ("2".equals(queryType) && StrUtil.hasEmpty(blockNumber)) {
			res.setError("495");
			return res(res);
		}
		String bizkey = null;
		if (!StrUtil.is0x40(bizid)
				|| (bizkey = TblUser.queryById(bizid)) == null) {
			res.setError("496");
			return res(res);
		}
		if (!isSign(signdata, bizkey, noncestr, req.getData())) {
			res.setError("497");
			return res(res);
		}
		RpcMethod method;
		if ("1".equals(queryType)) {
			method = new RpcMethod(Rpc.ETH_GETBLOCKBYHASH);
			method.addParams(blockHash);
			method.addParams(false);
		} else {
			method = new RpcMethod(Rpc.ETH_GETBLOCKBYNUMBER);
			method.addParams(blockNumber);
			method.addParams(false);
		}

		Data dd = Rpc.request(nodeurl, method);
		Response.Data resData = null;
		if (dd instanceof DataObj) {
			DataObj.Trade trade = ((DataObj) dd).getResult();
			resData = res.new Data();
			resData.setBlockNumber(StrUtil.Hex2Int(trade.getBlockNumber()));
			resData.setBlockHash(trade.getBlockHash());
			resData.setParentHash(trade.getParentHash());
			resData.setMinerAddr(trade.getMiner());
			resData.setDifficulty(StrUtil.Hex2Int(trade.getDifficulty()));
			resData.setTotalDifficulty(StrUtil.Hex2Int(trade
					.getTotalDifficulty()));
			resData.setExtraData(trade.getExtraData());
			resData.setBlockSize(StrUtil.Hex2Int(trade.getSize()));
			resData.setGasLimit(StrUtil.Hex2Int(trade.getGasLimit()));
			resData.setGasUsed(StrUtil.Hex2Int(trade.getGasUsed()));
			resData.setTransactionHash(trade.getTransactionsRoot());
			res.setResponse(resData);
		} else if (dd == null) {
			res.setError("498");
			return res(res);
		} else {
			res.setError("499");
			return res(res);
		}

		return res(res);
	}

	
	@POST
	@Path("/v1/queryTransactionNum")
	public Response queryTransactionNum(ReqBlockInfo req) {
		logger.info("req: " + JSON.toJson(req));
		Response res = new Response();
		String nodeurl = null;
		String bizid = req.getBizid();
		String noncestr = req.getNoncestr();
		String signdata = req.getSigndata();
		ReqBlockInfo.Data data = null;
		if (StrUtil.hasEmpty(bizid, noncestr, signdata) //
				|| noncestr.length() != Request.NONCESTR_LENGTH //
				|| (data = req.getData()) == null //
				|| !StrUtil.isUrl(nodeurl = data.getNodeurl())
				|| StrUtil.isUrl(data.getQueryType())) {//
			res.setError("495");
			return res(res);
		}
		String queryType = data.getQueryType();
		String blockNumber = data.getBlockNumber();
		String blockHash = data.getBlockHash();
		if (!"1".equals(queryType) && !"2".equals(queryType)) {
			res.setError("495");
			return res(res);
		} else if ("1".equals(queryType) && StrUtil.hasEmpty(blockHash)) {
			res.setError("495");
			return res(res);
		} else if ("2".equals(queryType) && StrUtil.hasEmpty(blockNumber)) {
			res.setError("495");
			return res(res);
		}
		String bizkey = null;
		if (!StrUtil.is0x40(bizid)
				|| (bizkey = TblUser.queryById(bizid)) == null) {
			res.setError("496");
			return res(res);
		}
		if (!isSign(signdata, bizkey, noncestr, req.getData())) {
			res.setError("497");
			return res(res);
		}
		RpcMethod method;
		if ("1".equals(queryType)) {
			method = new RpcMethod(Rpc.ETH_GETBLOCKTRANSACTIONCOUNTBYHASH);
			method.addParams(blockHash);
		} else {
			method = new RpcMethod(Rpc.ETH_GETBLOCKTRANSACTIONCOUNTBYNUMBER);
			method.addParams(blockNumber);
		}

		Data dd = Rpc.request(nodeurl, method);
		String transactionNumber = null;
		if (dd instanceof DataStr) {
			transactionNumber = ((DataStr) dd).getResult();
			res.getResponse().setTransactionNumber(
					StrUtil.Hex2Int(transactionNumber));
		} else if (dd == null) {
			res.setError("498");
			return res(res);
		} else {
			res.setError("499");
			return res(res);
		}

		return res(res);
	}

	
	@POST
	@Path("/v1/queryAccTransactionCount")
	public Response queryAccTransactionCount(ReqQueryAcc req) {
		logger.info("req: " + JSON.toJson(req));
		Response res = new Response();
		String nodeurl = null;
		String bizid = req.getBizid();
		String noncestr = req.getNoncestr();
		String signdata = req.getSigndata();
		ReqQueryAcc.Data data = null;
		if (StrUtil.hasEmpty(bizid, noncestr, signdata) //
				|| noncestr.length() != Request.NONCESTR_LENGTH //
				|| (data = req.getData()) == null //
				|| !StrUtil.isUrl(nodeurl = data.getNodeurl())) {//
			res.setError("495");
			return res(res);
		}
		String accountAddr = data.getAccountAddr();
		String blockNumber = data.getBlockNumber();
		if (StrUtil.hasEmpty(accountAddr)) {
			accountAddr = bizid;
		}
		if(StrUtil.hasEmpty(blockNumber)){
			blockNumber="latest"; 
		}
		String bizkey = null;
		if (!StrUtil.is0x40(bizid)
				|| (bizkey = TblUser.queryById(bizid)) == null) {
			res.setError("496");
			return res(res);
		}
		if (!isSign(signdata, bizkey, noncestr, req.getData())) {
			res.setError("497");
			return res(res);
		}
		RpcMethod method = new RpcMethod(Rpc.ETH_GETTRANSACTIONCOUNT);
		method.addParams(accountAddr);
		method.addParams(blockNumber);

		Data dd = Rpc.request(nodeurl, method);
		String accTransactionCount = null;
		if (dd instanceof DataStr) {
			accTransactionCount = ((DataStr) dd).getResult();
			res.getResponse().setAccTransactionCount(
					StrUtil.Hex2Int(accTransactionCount));
		} else if (dd == null) {
			res.setError("498");
			return res(res);
		} else {
			res.setError("499");
			return res(res);
		}

		return res(res);
	}

	@POST
	@Path("/adv/inputtochain")
	public Response advinputtochain(ReqAdvInput req) {
		logger.info("req: " + JSON.toJson(req));
		Response res = new Response();
		String bizid = req.getBizid();
		String noncestr = req.getNoncestr();
		String signdata = req.getSigndata();
		ReqAdvInput.Data data = null;
		String input = null;
		String from = null;
		String to = null;
		if (StrUtil.hasEmpty(bizid, noncestr, signdata) //
				|| noncestr.length() != Request.NONCESTR_LENGTH //
				|| (data = req.getData()) == null //
				|| ((from = data.getFrom()) != null && !StrUtil.is0x40(from)) //
				|| ((to = data.getTo()) != null && !StrUtil.is0x40(to))) { //
			res.setError("495");
			return res(res);
		}
		if ((input = data.getInput()) == null || !StrUtil.is0x128(input)) {
			res.setError("494");
			return res(res);
		}
		String bizkey = null;
		if (!StrUtil.is0x40(bizid)
				|| (bizkey = TblUser.queryById(bizid)) == null) {
			res.setError("496");
			return res(res);
		}
		if (!isSign(signdata, bizkey, noncestr, req.getData())) {
			res.setError("497");
			return res(res);
		}
		if (from == null) {
			from = bizid;
		}
		input += bizid.substring(2);
		input += DateUtil.getDateTime(new Date());
		RpcMethod transMethod = new RpcMethod(Rpc.ETH_SENDTRANSACTION);
		if (to == null) {
			transMethod.addParams(from, input);
		} else {
			transMethod.addParams(from, to, input);
		}
		Data dd = Rpc.request(transMethod);
		String transactionid = null;
		if (dd instanceof DataStr) {
			transactionid = ((DataStr) dd).getResult();
			res.getResponse().setTransactionid(transactionid);
		} else if (dd == null) {
			res.setError("498");
			return res(res);
		} else {
			res.setError("499");
			return res(res);
		}
		// 同步记录交易
		TblInputtochain.save(Config.PUBLIC_RPC, bizid, from, to, input,
				transactionid);

		// 异步记录交易
		// TblInputtochain.asyncSave(Config.PUBLIC_RPC, bizid, from, to, input,
		// transactionid);
		// 异步查询交易详情并入库
		// if (transactionid != null) {
		// TblTransaction.asyncSave(transactionid);
		// }
		return res(res);
	}

	@POST
	@Path("/adv/queryfromchain")
	public Response advqueryfromchain(ReqAdvAuth req) {
		logger.info("req: " + JSON.toJson(req));
		Response res = new Response();
		String bizid = req.getBizid();
		String noncestr = req.getNoncestr();
		String signdata = req.getSigndata();
		ReqAdvAuth.Data data = null;
		String transactionid = null;
		if (StrUtil.hasEmpty(bizid, noncestr, signdata) //
				|| noncestr.length() != Request.NONCESTR_LENGTH //
				|| (data = req.getData()) == null //
				|| (transactionid = data.getTransactionid()) == null //
				|| !StrUtil.is0x64(transactionid)) {//
			res.setError("495");
			return res(res);
		}
		String bizkey = null;
		if (!StrUtil.is0x40(bizid)
				|| (bizkey = TblUser.queryById(bizid)) == null) {
			res.setError("496");
			return res(res);
		}
		if (!isSign(signdata, bizkey, noncestr, req.getData())) {
			res.setError("497");
			return res(res);
		}
		RpcMethod method = new RpcMethod(Rpc.ETH_GETTRANSACTIONBYHASH);
		method.addParams(transactionid);
		Data dd = Rpc.request(method);
		Response.Data resData = null;
		if (dd instanceof DataObj) {
			DataObj.Trade trade = ((DataObj) dd).getResult();
			resData = res.new Data();
			String input = trade.getInput();
			String blockNumber = trade.getBlockNumber();
			String index = trade.getTransactionIndex();
			if (!StrUtil.hasEmpty(input)) {
				if (input.startsWith("0x")) {
					input = input.substring(2);
				}
				if (input.length() > 128) {
					input = input.substring(0, 128);
				}
			}
			resData.setBlockHash(trade.getBlockHash());
			resData.setBlockNumber(StrUtil.Hex2Int(blockNumber));
			resData.setContent(input);
			resData.setTransactionIndex(StrUtil.Hex2Int(index));
			res.setResponse(resData);
		} else if (dd == null) {
			res.setError("498");
			return res(res);
		} else {
			res.setError("499");
			return res(res);
		}
		// 同步保存
		// TblAuthfromchain.save(nodeurl, bizid, transactionid,
		// resData.getBlockHash(), resData.getBlockNumber(),
		// resData.getContent(), resData.getTransactionIndex());
		// 异步保存
		TblQueryfromchain.asyncSave(Config.PUBLIC_RPC, bizid, transactionid,
				resData.getBlockHash(), resData.getBlockNumber(),
				resData.getContent(), resData.getTransactionIndex());
		return res(res);
	}

	/**
	 * 公链锚定参数设置
	 */
	@POST
	@Path("/adv/setanchorparams")
	public Response setanchorparams(ReqAnchorCofig req) {
		logger.info("req: " + JSON.toJson(req));
		Response res = new Response();
		String bizid = req.getBizid();
		String noncestr = req.getNoncestr();
		String signdata = req.getSigndata();
		String paramtype = "";
		String startdate = null;
		Date date = null;
		String anchorinterval = "";
		String anchorrecords = null;
		int records = 0;
		ReqAnchorCofig.Data data = null;
		if (StrUtil.hasEmpty(bizid, noncestr, signdata) //
				|| noncestr.length() != Request.NONCESTR_LENGTH //
				|| (data = req.getData()) == null //
				|| (paramtype = data.getParamtype()) == null//
				|| (!"1".equals(paramtype) && !"2".equals(paramtype)
						&& !"3".equals(paramtype) && !"4".equals(paramtype))//
				|| ((startdate = data.getStartdate()) != null && !StrUtil
						.isDateStr14(startdate))) { //
			res.setError("495");
			return res(res);
		}
		if ("1".equals(paramtype) || "3".equals(paramtype)
				|| "4".equals(paramtype)) {
			anchorinterval = data.getAnchorinterval();
			if (anchorinterval == null || "".equals(anchorinterval)) {
				res.setError("495");
				return res(res);
			}
		}
		if ("2".equals(paramtype) || "3".equals(paramtype)
				|| "4".equals(paramtype)) {
			anchorrecords = data.getAnchorrecords();
			if (StrUtil.hasEmpty(anchorrecords)
					|| !anchorrecords.matches("[0-9]+")
					|| Integer.valueOf(anchorrecords) == 0) {
				res.setError("495");
				return res(res);
			} else {
				records = Integer.valueOf(anchorrecords);
			}
		}
		String bizkey = null;
		if (!StrUtil.is0x40(bizid)
				|| (bizkey = TblUser.queryById(bizid)) == null) {
			res.setError("496");
			return res(res);
		}
		if (!isSign(signdata, bizkey, noncestr, req.getData())) {
			res.setError("497");
			return res(res);
		}
		if (startdate == null) {
			date = new Date();
		} else {
			date = DateUtil.getDate(startdate);
		}

		AnchorcofigEntity anchorcofigEntity = TblAnchorcofig
				.selectAllBybizid(bizid);
		int anchorconfigid = 0;
		if (anchorcofigEntity != null
				&& anchorcofigEntity.getAnchorcofigid() != null) {

			// 停止定时任务
			NewTimerTask.stop(bizid, Config.timerMap.get(bizid));
			anchorconfigid = anchorcofigEntity.getAnchorcofigid();
			TblAnchorcofig.update(anchorcofigEntity.getAnchorcofigid(),
					paramtype, bizid, anchorinterval, anchorrecords, date);
			// TblAnchorcofig.deleteBybizid(bizid);
			// TblAnchorrecord.deleteBybizid(bizid);
		} else {
			// 同步保存
			anchorconfigid = TblAnchorcofig.save(paramtype, bizid,
					anchorinterval, anchorrecords, date);
		}

		// // 查询交易
		List<InputtochainEntity> trans = TblInputtochain.gettransactionids(
				bizid, anchorconfigid, records, "0");
		if (trans.size() > 0) {
			NewTimerTask.rpc(trans, anchorconfigid, bizid);
		}
		if (anchorconfigid != 0) {
			if (!"2".equals(paramtype)) {
				NewTimerTask.start(paramtype, bizid, anchorconfigid,
						DateUtil.getDateTime(date), anchorinterval, records);
			}
			res.getResponse().setAnchorconfigid(String.valueOf(anchorconfigid));
		}
		return res(res);
	}

	/**
	 * 公链锚定参数查询
	 */
	@POST
	@Path("/adv/getanchorparams")
	public Response getanchorparams(ReqGetAnchorCofig req) {
		logger.info("req: " + JSON.toJson(req));
		Response res = new Response();
		String bizid = req.getBizid();
		String noncestr = req.getNoncestr();
		String signdata = req.getSigndata();
		String anchorconfigid;
		ReqGetAnchorCofig.Data data = null;
		if (StrUtil.hasEmpty(bizid, noncestr, signdata) //
				|| noncestr.length() != Request.NONCESTR_LENGTH //
				|| (data = req.getData()) == null //
				|| (anchorconfigid = data.getAnchorconfigid()) == null) { //
			res.setError("495");
			return res(res);
		}
		String bizkey = null;
		if (!StrUtil.is0x40(bizid)
				|| (bizkey = TblUser.queryById(bizid)) == null) {
			res.setError("496");
			return res(res);
		}
		if (!isSign(signdata, bizkey, noncestr, req.getData())) {
			res.setError("497");
			return res(res);
		}
		// 同步保存
		AnchorcofigEntity anchorcofig = TblAnchorcofig
				.selectById(anchorconfigid);
		if (anchorcofig != null) {
			Response.Data resData = res.new Data();
			resData.setParamtype(anchorcofig.getAnchortype());
			resData.setStartdate(DateUtil.getDateTime(anchorcofig
					.getAnchorstartdate()));
			if (!"2".equals(anchorcofig.getAnchortype())) {
				resData.setAnchorinterval(anchorcofig.getAnchorinterval());
			}
			if (!"1".equals(anchorcofig.getAnchortype())) {
				resData.setAnchorrecords(anchorcofig.getAnchorrecords());
			}
			resData.setCreatedate(DateUtil.getDateTime(anchorcofig
					.getReccrtts()));
			res.setResponse(resData);
		}
		return res(res);
	}

	/**
	 * 公链锚定结果验证
	 */
	@POST
	@Path("/adv/checkanchorresults")
	public Response checkanchorresults(ReqAdvAuth req) {
		logger.info("req: " + JSON.toJson(req));
		Response res = new Response();
		String bizid = req.getBizid();
		String noncestr = req.getNoncestr();
		String signdata = req.getSigndata();
		ReqAdvAuth.Data data = null;
		String transactionid = null;
		if (StrUtil.hasEmpty(bizid, noncestr, signdata) //
				|| noncestr.length() != Request.NONCESTR_LENGTH //
				|| (data = req.getData()) == null //
				|| (transactionid = data.getTransactionid()) == null //
				|| !StrUtil.is0x64(transactionid)) {//
			res.setError("495");
			return res(res);
		}
		String bizkey = null;
		if (!StrUtil.is0x40(bizid)
				|| (bizkey = TblUser.queryById(bizid)) == null) {
			res.setError("496");
			return res(res);
		}
		if (!isSign(signdata, bizkey, noncestr, req.getData())) {
			res.setError("497");
			return res(res);
		}
		AnchorrecordEntity anchorrecordEntity = TblAnchorrecord
				.getanchorbytransid(bizid, transactionid);
		if (anchorrecordEntity != null) {
			List<String> list = TblInputtochain.getinputs(bizid,
					anchorrecordEntity.getLastid());
			Response.Data resData = res.new Data();
			resData.setContents(list);
			resData.setTxid(anchorrecordEntity.getAnchortxid());
			res.setResponse(resData);
		}
		return res(res);
	}

	/**
	 * 公链锚定结果查询
	 */
	@POST
	@Path("/adv/getanchorresults")
	public Response getanchorresults(ReqAnchorRecord req) {
		logger.info("req: " + JSON.toJson(req));
		Response res = new Response();
		String bizid = req.getBizid();
		String noncestr = req.getNoncestr();
		String signdata = req.getSigndata();
		String begindate;
		String enddate;
		String anchorconfigid;
		ReqAnchorRecord.Data data = null;
		if (StrUtil.hasEmpty(bizid, noncestr, signdata) //
				|| noncestr.length() != Request.NONCESTR_LENGTH //
				|| (data = req.getData()) == null //
				|| (anchorconfigid = data.getAnchorconfigid()) == null
				|| ((begindate = data.getBegindate()) != null && !StrUtil
						.isDateStr14(begindate))
				|| ((enddate = data.getEnddate()) != null && !StrUtil
						.isDateStr14(enddate))) {
			res.setError("495");
			return res(res);
		}
		String bizkey = null;
		if (!StrUtil.is0x40(bizid)
				|| (bizkey = TblUser.queryById(bizid)) == null) {
			res.setError("496");
			return res(res);
		}
		if (!isSign(signdata, bizkey, noncestr, req.getData())) {
			res.setError("497");
			return res(res);
		}
		// 同步保存
		List<String> list = TblAnchorrecord.getanchorresults(bizid,
				anchorconfigid, begindate, enddate);
		if (list != null && list.size() > 0) {
			Response.Data resData = res.new Data();
			resData.setTransactionids(list);
			res.setResponse(resData);
		}
		return res(res);
	}

	/**
	 * 锚定参数查询
	 */
	@POST
	@Path("/anchorparam")
	public Response anchorparam(ReqAnchor req) {
		logger.info("req: " + JSON.toJson(req));
		Response res = new Response();
		String nodeurl = null; // req.getNodeurl();
		String bizid = req.getBizid();
		String noncestr = req.getNoncestr();
		String signdata = req.getSigndata();
		ReqAnchor.Data data = null;
		String date = null;
		if (StrUtil.hasEmpty(nodeurl, bizid, noncestr, signdata) //
				|| noncestr.length() != Request.NONCESTR_LENGTH //
				|| !StrUtil.isUrl(nodeurl) //
				|| (data = req.getData()) == null //
				|| ((date = data.getDate()) != null && !StrUtil
						.isDateStr8(date))) { //
			res.setError("495");
			return res(res);
		}
		String bizkey = null;
		if (!StrUtil.is0x40(bizid)
				|| (bizkey = TblUser.queryById(bizid)) == null) {
			res.setError("496");
			return res(res);
		}
		if (!isSign(signdata, bizkey, noncestr, req.getData())) {
			res.setError("497");
			return res(res);
		}
		String transactionid = TblDailytxid.find(date);
		if (transactionid != null) {
			res.getResponse().setTransactionid(transactionid);
		}
		return res(res);
	}

	/**
	 * 锚定数据验证 查询一笔公有链上的记录，不需要入库
	 */
	@POST
	@Path("/authanchordata")
	public Response authanchordata(ReqAuth req) {
		logger.info("req: " + JSON.toJson(req));
		Response res = new Response();
		String nodeurl = null; // req.getNodeurl();
		String bizid = req.getBizid();
		String noncestr = req.getNoncestr();
		String signdata = req.getSigndata();
		ReqAuth.Data data = null;
		String transactionid = null;
		if (StrUtil.hasEmpty(nodeurl, bizid, noncestr, signdata) //
				|| noncestr.length() != Request.NONCESTR_LENGTH //
				|| !StrUtil.isUrl(nodeurl) //
				|| (data = req.getData()) == null //
				|| (transactionid = data.getTransactionid()) == null //
				|| !StrUtil.is0x64(transactionid)) {//
			res.setError("495");
			return res(res);
		}
		String bizkey = null;
		if (!StrUtil.is0x40(bizid)
				|| (bizkey = TblUser.queryById(bizid)) == null) {
			res.setError("496");
			return res(res);
		}
		if (!isSign(signdata, bizkey, noncestr, req.getData())) {
			res.setError("497");
			return res(res);
		}
		RpcMethod method = new RpcMethod(Rpc.ETH_GETTRANSACTIONBYHASH);
		method.addParams(transactionid);
		Data dd = Rpc.request(method);
		Response.Data resData = null;
		if (dd instanceof DataObj) {
			DataObj.Trade trade = ((DataObj) dd).getResult();
			resData = res.new Data();
			resData.setBlockHash(trade.getBlockHash());
			resData.setBlockNumber(trade.getBlockNumber());
			resData.setContent(trade.getInput());
			resData.setTransactionIndex(trade.getTransactionIndex());
			res.setResponse(resData);
		} else if (dd == null) {
			res.setError("498");
		} else {
			res.setError("499");
		}
		return res(res);
	}

	/**
	 * 签名验证
	 */
	private boolean isSign(String signdata, String bizkey, String noncestr,
			Request.Data data) {
		String signBody = bizkey + noncestr + JSON.toJson(data);
		String signed = SHA1.encode(signBody);
		System.out.println("目标签名:" + signdata);
		System.out.println("待签名值:" + signBody);
		System.out.println("签名结果:" + signed);
		return signdata.equals(signed);
	}

	private Response res(Response res) {
		logger.info("res: " + JSON.toJson(res));
		return res;
	}
}
